<?php

namespace W3;

use W3\Asset;
use function add_action;

!defined('W3_ROOT_DIR') AND exit;

/**
 * 前台初始化模块
 *
 * @author edikud
 * @date 2022/10/22
 * @copyright Copyright (c) 2022 W3 (http://www.mcooo.com)
 * @license GNU General Public License 2.0
 */
class Cms extends Widget
{
    /**
     * 初始化
     *
     * @access protected
     * @return void
     */
    protected function init()
    {
		# 定义变量默认数据
        $this->parameter([
			
			# 设置主体
			'main' => 'init',	
			
		], true);

		# 默认的404响应
		Error::error404(function (){
				
			# 实现前台支持自定义404模板
			$this->widget('Module\Cms\Error')->view();
		});

        add_action( 'header' , function () 
		{
		    echo Asset::styles();
		    echo Asset::scripts();
        });

        add_action( 'footer' , function () 
		{
		    echo Asset::scripts(true);
        });

        add_action( 'call@view' ,        [Cms::class, '_view']);
        add_action( 'call@themeUrl' ,    [Cms::class, '_themeUrl']);	
        add_action( 'call@comments' ,    [Cms::class, '_comments']);
        add_action( 'call@template' ,    [Cms::class, '_template']);
        add_action( 'call@is' ,          [Cms::class, '_is']);
        add_action( 'call@header' ,      [Cms::class, '_header']);	
        add_action( 'call@footer' ,      [Cms::class, '_footer']);
        add_action( 'call@theNext' ,     [Cms::class, '_theNext']);	
        add_action( 'call@thePrev' ,     [Cms::class, '_thePrev']);
        add_action( 'call@attachments' , [Cms::class, '_attachments']);
        add_action( 'call@related' ,     [Cms::class, '_related']);
    }

    /**
     * 入口函数
     *
     * @access public
     * @return void
     */
    public function execute()
    {

		Token::set($this->auth->hasLogin() ? $this->config->secret . '&' . $this->auth->uid : $this->config->secret);

        /** 初始化皮肤函数 */
        $functionsFile = W3_TEMPLATE_DIR . $this->config->theme . '/functions.php';
        if (file_exists($functionsFile)) {
            require_once $functionsFile;
        }
	}

    /**
     * 获取模板皮肤路径
     *
     * @param mixed $widget	 所属调用的组件
	 * @param string $file (可选)要附加的文件路径
     * @return mixed
     */
    public static function _themeUrl(Widget $widget, ?string $file = null, ?string $theme = null, bool $echo = true)
    {
        if (empty($theme)) {
            $theme = $widget->config->theme;
        }
        $result = $widget->config->templateUrl . $theme . '/';
        if (!empty($file)) {
            $result .= ltrim($file, '/');
        }
        if ($echo) {
            echo $result;
        } else {
            return $result;
        }
	}

    /**
     * 获取评论归档对象
     *
     * @param mixed $widget	 所属调用的组件
     * @return mixed
     */
    public static function _comments(Widget $widget)
    {
        $parameter = [
            'parentId'      => $widget->cid,
            'parentRow'     => $widget->row,
            'respondId'     => $widget->respondId,
            'commentPage'   => $widget->request->filter('int')->commentPage,
            'allowComment'  => $widget->allow('comment'),
            'before'        =>  '<ol class="comment-list">',
            'after'         =>  '</ol>',
            'dateFormat'    =>  $widget->config->commentDateFormat,
        ];

        return $widget->widget('Comment\Rows', $parameter);
	}

    /**
     * template
     *
     * @param mixed $widget	 所属调用的组件
     * @return mixed
     */
    public static function _template(Widget $widget, ?string $name = null)
    {
        # 输出模板
        $widget->require(W3_TEMPLATE_DIR . $widget->config->theme . '/' . $name . '.php');
	}

    /**
     * 判断类型和名称
     *
     * @param string $type 类型
     * @param string $alias 名称
     * @return boolean
     */
    public static function _is(Widget $widget, string $type, ?string $alias = null)
    {
	    $parameter = $widget->parameter;

        return ($type == $parameter->main
	        || (($parameter->single ? 'single' : 'archive') == $type && 'index' != $parameter->main)
		    || ('index' == $type && $parameter->front)) && (empty($alias) || $alias == $parameter->alias);
	}

    /**
     * 输出header
     *
     * @param mixed $widget	 所属调用的组件
     * @return void
     */
    public static function _header(Widget $widget, $rule = NULL)
    {
        $header = [];
        $allows = [
            'description'   =>  htmlspecialchars($widget->parameter->description),
            'keywords'      =>  htmlspecialchars($widget->parameter->keywords),
		    'commentReply' => 1,
        ];

        if (!empty($rule)) {
            parse_str($rule, $rules);
            $allows = array_merge($allows, $rules);
        }

        if (!empty($allows['description'])) {
            $header[] = '<meta name="description" content="' . $allows['description'] . '" />';
        }

        if (!empty($allows['keywords'])) {
            $header[] = '<meta name="keywords" content="' . $allows['keywords'] . '" />';
        }

        if ($widget->auth->hasLogin() && $widget->config->commentsThreaded && $widget->is('single')) {
            if ('' != $allows['commentReply']) {
                if (1 == $allows['commentReply']) {
                    $js = "
(function () {
    window.comment = {
        dom : function (id) {
            return document.getElementById(id);
        },
    
        create : function (tag, attr) {
            var el = document.createElement(tag);
        
            for (var key in attr) {
                el.setAttribute(key, attr[key]);
            }
        
            return el;
        },

        reply : function (cid, coid) {
            var comment = this.dom(cid), parent = comment.parentNode,
                response = this.dom('" . $widget->respondId . "'), input = this.dom('comment-parent'),
                form = 'form' == response.tagName ? response : response.getElementsByTagName('form')[0],
                textarea = response.getElementsByTagName('textarea')[0];

            if (null == input) {
                input = this.create('input', {
                    'type' : 'hidden',
                    'name' : 'parent',
                    'id'   : 'comment-parent'
                });

                form.appendChild(input);
            }

            input.setAttribute('value', coid);

            if (null == this.dom('comment-form-place-holder')) {
                var holder = this.create('div', {
                    'id' : 'comment-form-place-holder'
                });

                response.parentNode.insertBefore(holder, response);
            }

            comment.appendChild(response);
            this.dom('cancel-comment-reply-link').style.display = '';

            if (null != textarea && 'text' == textarea.name) {
                textarea.focus();
            }

            return false;
        },

        cancelReply : function () {
            var response = this.dom('{$widget->respondId}'),
            holder = this.dom('comment-form-place-holder'), input = this.dom('comment-parent');

            if (null != input) {
                input.parentNode.removeChild(input);
            }

            if (null == holder) {
                return true;
            }

            this.dom('cancel-comment-reply-link').style.display = 'none';
            holder.parentNode.insertBefore(response, holder);
            return false;
        }
    };
})();";

                    add_script('commentReply', $js);
                } else {
					add_script('commentReply', $allows['commentReply']);
                }
            }
        }

        /** 输出header */
        echo implode("\n", array_filter($header));
		
        /** 插件接口 */
		\do_action('header', $widget);
	}
	
    /**
     * 输出footer
     *
     * @param mixed $widget	 所属调用的组件
     * @return mixed
     */
    public static function _footer(Widget $widget)
    {
		/** 插件接口 */
        \do_action('footer', $widget);
	}

    /**
     * 输出视图
     *
     * @param mixed $widget	 所属调用的组件
     * @return mixed
     */
    public static function _view(Widget $widget)
    {
		static $initialized = false;
		
		# 防止嵌套调用, 发生死循环
		if ($initialized){
				
			throw new Exception('禁止嵌套调用', 403);
			
			return ;
		}
			
		$initialized = true;
			
        $validated = false;
        $themeFile = $widget->parameter->themeFile;
        $themeDir = $widget->parameter->themeDir ?? $widget->config->themeDir;
        $type = $widget->parameter->main;
			
        #~ 自定义模板
        if (!empty($themeFile)) {
            $themeFile = $themeDir . $themeFile . '.php';
            if (file_exists($themeFile)) {
                $validated = true;
            }
        }
			
        if (!$validated && !empty($type)) {
				
            #~ 首先找具体路径, 比如 category/default.php
            if (!$validated && !empty($widget->parameter->alias)) {
                $file = $type . '/' . $widget->parameter->alias;
                $themeFile = $themeDir . $file . '.php';
                if (file_exists($themeFile)) {
                    $validated = true;
                }
            }
				
            #~ 然后找类型路径, 比如 category.php
            if (!$validated) {
                $file = $type;
                $themeFile = $themeDir . $file . '.php';
                if (file_exists($themeFile)) {
                    $validated = true;
                }
            }
				
            #~ 最后找归档路径, 比如 archive.php
            if (!$validated && 'index' != $type) {
                $file = $widget->parameter->single ? 'single' : 'archive';
                $themeFile = $themeDir . $file . '.php';
                if (file_exists($themeFile)) {
                    $validated = true;
                }
            }
				
            if (!$validated) {
                $file = 'index';
                $themeFile = $themeDir . $file . '.php';
                if (file_exists($themeFile)) {
                    $validated = true;
                }
            }
        }
			
        # 文件不存在
        if (!$validated) {
            return;
        }

        # 输出模板
        $widget->require($themeFile);
	}

    /**
     * 获取附件对象
     *
     * @access public
     * @param integer $limit 最大个数
     * @param integer $offset 重新
     * @return Widget_Attachs_List
     */
    public static function _attachments(Widget $widget, int $limit = 0, int $offset = 0)
    {
        return $widget->widget( 'Attachs\Rows@'  . $widget->type . '-' . $widget->cid . '-' . $limit . '-' . $offset, array(
		    'type'      => $widget->type,
		    'cid'        => $widget->cid,
            'limit'     => $limit,
            'offset'    => $offset
        ));
    }

    /**
     * 显示下一个内容的标题链接
     *
     * @access public
     * @param string $format 格式
     * @param string $default 如果没有下一篇,显示的默认文字
     * @param array $custom 定制化样式
     * @return void
     */
    public static function _theNext(Widget $widget, $format = '%s', $default = NULL, $custom = array())
    {
		$row = $widget->db->select('table.relate.cid')
		    ->from('table.relate')
			->where('table.relate.cid > ?', $widget->cid)
		    ->where('table.relate.mid = ?', $widget->mid)
            ->order('table.relate.cid', 'ASC')
            ->limit(1)
			->fetch();

        $content = $row ? $widget->db->select()->from('table.contents')
		    ->where('table.contents.cid = ?', $row['cid'])
            ->limit(1)
			->fetch() : '';

        if ($content) {
            $content = $widget->filter($content);
            $default = array(
                'title' => NULL,
                'tagClass' => NULL
            );
            $custom = array_merge($default, $custom);
            extract($custom);

            $linkText = empty($title) ? $content['title'] : $title;
            $linkClass = empty($tagClass) ? '' : 'class="' . $tagClass . '" ';
            $link = '<a ' . $linkClass . 'href="' . $content['permalink'] . '" title="' . $content['title'] . '">' . $linkText . '</a>';

            printf($format, $link);
        } else {
            echo $default;
        }
    }

    /**
     * 显示上一个内容的标题链接
     *
     * @access public
     * @param string $format 格式
     * @param string $default 如果没有上一篇,显示的默认文字
     * @param array $custom 定制化样式
     * @return void
     */
    public static function _thePrev(Widget $widget, $format = '%s', $default = NULL, $custom = array())
    {
		$row = $widget->db->select('table.relate.cid')
		    ->from('table.relate')
			->where('table.relate.cid < ?', $widget->cid)
		    ->where('table.relate.mid = ?', $widget->mid)
            ->order('table.relate.cid', 'DESC')
            ->limit(1)
			->fetch();

        $content = $row ? $widget->db->select()->from('table.contents')
		    ->where('table.contents.cid = ?', $row['cid'])
            ->limit(1)
			->fetch() : '';

        if ($content) {
            $content = $widget->filter($content);
            $default = array(
                'title' => NULL,
                'tagClass' => NULL
            );
            $custom = array_merge($default, $custom);
            extract($custom);

            $linkText = empty($title) ? $content['title'] : $title;
            $linkClass = empty($tagClass) ? '' : 'class="' . $tagClass . '" ';
            $link = '<a ' . $linkClass . 'href="' . $content['permalink'] . '" title="' . $content['title'] . '">' . $linkText . '</a>';

            printf($format, $link);
        } else {
            echo $default;
        }
    }

    /**
     * 获取关联内容组件
     *
     * @access public
     * @param integer $limit 输出数量
     * @param string $type 关联类型
     * @return Widget
     */
    public static function _related(Widget $widget, $limit = 5, $type = NULL)
    {
        $type = strtolower($type);

        switch ($type) {
            case 'author':
                /** 如果访问权限被设置为禁止,则tag会被置为空 */
                return $widget->widget('Contents\Related\Author',
                ['cid' => $widget->cid, 'type' => $widget->type, 'uid' => $widget->uid, 'limit' => $limit]);
            default:
                /** 如果访问权限被设置为禁止,则tag会被置为空 */
                return $widget->widget('Contents\Related',
                ['cid' => $widget->cid, 'type' => $widget->type, 'tags' => $widget->tags, 'limit' => $limit]);
        }
    }
	
}

